package server;

import util.HttpProtocolUtil;
import util.ServletUtil;
import util.StaticResourceUtil;
import util.ThreadPoolExecutorUtil;
import webresources.Mapper;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.*;

/**
 * Minicat的主类
 */
public class Bootstrap {

    private Mapper mapper = new Mapper();

    /**
     * Minicat启动
     * @param version       Minicat版本号
     * @throws Exception
     */
    public void start(String version) throws Exception {
        // 加载解析相关的配置，server.xml web.xml
        this.mapper = ServletUtil.loadServlet(this.getClass().getClassLoader());
        // 获取监听端口号
        String port = mapper.getPort();
        if (port == null || port.length() == 0) {
            throw new Exception("监听端口号为空");
        }
        // 创建服务端socket
        ServerSocket serverSocket = new ServerSocket();
        serverSocket.setReuseAddress(true);
        serverSocket.bind(new InetSocketAddress("localhost", Integer.parseInt(port)));
        if ("1.0".equals(version)) {
            System.out.println("=========>>>>>>1.0版本 返回字符串");
            minicatOneVersion(serverSocket);
        } else if ("2.0".equals(version)) {
            System.out.println("=========>>>>>>2.0版本 请求静态资源");
            minicatTowVersion(serverSocket);
        } else if ("3.0".equals(version)) {
            System.out.println("=========>>>>>>3.0版本 请求动态资源");
            minicatThreeVersion(serverSocket);
        } else if ("4.0".equals(version)) {
            System.out.println("=========>>>>>>4.0版本 多线程改造（不使用线程池）");
            minicatFourVersion(serverSocket);
        } else if ("5.0".equals(version)) {
            System.out.println("=========>>>>>>5.0版本 多线程改造（使用线程池）");
            minicatFiveVersion(serverSocket);
        } else {
            throw new Exception("配置版本号错误,未找到版本:" + version);
        }
    }

    /**
     * 1.0版本 返回字符串
     */
    private void minicatOneVersion(ServerSocket serverSocket) throws Exception {
        // 阻塞式监听
        while(true) {
            Socket socket = serverSocket.accept();
            // 有了socket，接收到请求，获取输出流
            OutputStream outputStream = socket.getOutputStream();
            String data = "Hello Minicat!";
            String responseText = HttpProtocolUtil.getHttpHeader200(data.getBytes().length) + data;
            outputStream.write(responseText.getBytes());
            socket.close();
        }
    }

    /**
     * 2.0版本 请求静态资源
     */
    private void minicatTowVersion(ServerSocket serverSocket) throws Exception {
        while(true) {
            Socket socket = serverSocket.accept();
            // 封装Request对象和Response对象
            Request request = new Request(socket.getInputStream());
            Response response = new Response(socket.getOutputStream());
            response.outputHtml(request.getUrl());
            socket.close();
        }
    }

    /**
     * 3.0版本 请求动态资源
     */
    private void minicatThreeVersion(ServerSocket serverSocket) throws Exception {
        while(true) {
            Socket socket = serverSocket.accept();
            // 封装Request对象和Response对象
            Request request = new Request(socket.getInputStream());
            Response response = new Response(socket.getOutputStream());
            // 查找servlet
            Servlet servlet = ServletUtil.queryServlet(request, socket, mapper);
            if(servlet == null) {
                // 静态资源处理
                response.outputHtml(request.getUrl());
            }else{
                // 动态资源servlet请求
                servlet.service(request,response);
            }
            socket.close();
        }
    }

    /**
     * 4.0版本 多线程改造（不使用线程池）
     */
    private void minicatFourVersion(ServerSocket serverSocket) throws Exception {
        while(true) {
            Socket socket = serverSocket.accept();
            RequestProcessor requestProcessor = new RequestProcessor(socket, mapper);
            requestProcessor.start();
        }
    }

    /**
     * 5.0版本 多线程改造（使用线程池）
     */
    private void minicatFiveVersion(ServerSocket serverSocket) throws Exception {
        // 获取线程池
        ThreadPoolExecutor pool = ThreadPoolExecutorUtil.getThreadPoolExecutor();
        while(true) {
            // 接收客户端请求
            Socket socket = serverSocket.accept();
            if (pool.getQueue().size() >= 1) {
                rejectRequest(socket);
                continue;
            }
            RequestProcessor requestProcessor = new RequestProcessor(socket, mapper);
            pool.submit(requestProcessor);
        }
    }

    /**
     * 服务器熔断
     * @param socket
     */
    private void rejectRequest(Socket socket) throws Exception {
        OutputStream outputStream = null;
        try {
            outputStream = socket.getOutputStream();
            String content = HttpProtocolUtil.getHttpHeader503("请稍后再试");
            outputStream.write(content.getBytes());
        } finally {
            StaticResourceUtil.close(socket, null, outputStream);
        }
    }

}
